package io.hepu.robotize.aop;

import io.hepu.robotize.auth.JRedis;
import io.hepu.robotize.exception.RequestLimitException;
import io.hepu.robotize.util.Servlets;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class RequestLimitAspect {
    private static final Logger logger = LoggerFactory.getLogger(RequestLimitAspect.class);

    @Before("@annotation(limit)")
    public void limit(JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = Servlets.getClientIp(request);
        String url = request.getRequestURL().toString();
        String key = "limit_req_".concat(url).concat("_").concat(ip);
        boolean isAllowed = isAllowed(limit, key);
        if (!isAllowed) {
            logger.info("[RequestUrl:{}], Exceeded the limit [{}] times in [{}] second, ip is [{}]", url, limit.times(), limit.period() / 1000, ip);
            throw new RequestLimitException("Request exceeds the limit times");
        }
    }

    private boolean isAllowed(RequestLimit limit, String key) {
        long times = JRedis.increment(key, 1);
        if (times == 1) {
            JRedis.expire(key, limit.period() / 1000);
        }
        return times < limit.times();
    }
}
